package automaton;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;

import utils.MyLogger;
import utils.TimeCounter;

import dataStructures.LoggedDast;
import dataStructures.index.*;
import dk.brics.automaton.Automaton;
/**
 * @author UserXP
 *	this class creates store and load automatons of the document's nodes
 */
public class XmlAutomatonManager extends LoggedDast{
	private String _path;
	
	public XmlAutomatonManager(String path)
	{
		if (path.endsWith("\\"))
		{
			_path = path;
		}
		else
		{
			_path = path + "\\";
		}
		
		new File(path).mkdirs();
		
	}
	@SuppressWarnings("unchecked")
	public HashMap<Integer,Integer> DeserializeAutomationMapping() throws Exception
	{
		FileInputStream fis = new FileInputStream(_path + "automatons.map");
		
		ObjectInputStream s = new ObjectInputStream(fis);
		
		return (HashMap<Integer,Integer>)s.readObject();
		
	}
	
	public void SerializeDocumentAutomatons(RouteToIdIndex routeIndex) throws Exception
	{
		HashMap<Integer, Integer> automatonsMapping = new HashMap<Integer, Integer>();
		
		QueryAutomaton automatonCreator = new QueryAutomaton();

		Iterator<ArrayList<Integer>> routesIteratr = routeIndex.RoutesIterator();
		
		
		int numberOfAutomatons = 0;
		TimeCounter timeCounter = new TimeCounter();
		AddLogEntry("starting to serialize automatons");
		int totalNodes = 0;
		while(routesIteratr.hasNext())
		{
			numberOfAutomatons++;
			ArrayList<Integer> serializedRoute = routesIteratr.next();
			ArrayList<Integer> nodesId = routeIndex.GetSerializedRouteNodesId(serializedRoute);
			//String idRoute = routesIteratr.next();
			//System.out.println(routeIndex.DeserializedRoute(idRoute));
			//String[] nodesId = routeIndex.GetNodesIndex(idRoute).split("#");
			
			//int representative = Integer.valueOf(nodesId[0]);
			
			int representative = nodesId.get(0);
			System.out.println("Building automaton to route with size of " + serializedRoute.size());
			Automaton A = automatonCreator.CreateQueriesAutomaton(routeIndex.DeserializedRoute(serializedRoute));
			String automatonPath = _path + String.valueOf(representative) + ".dfa";
			
			FileOutputStream fos = new FileOutputStream(automatonPath);
			
			A.store(fos);
			
			fos.close();
			
			//for(int id: nodesId)
			{
				//automatonsMapping.put(id,representative);
			}
			totalNodes+=nodesId.size();
			System.out.println("Done with " + totalNodes + " Nodes...");
		}
		
		FileOutputStream fos = new FileOutputStream(_path + "automatons.map");
		
		ObjectOutputStream s = new ObjectOutputStream(fos);
		
		s.writeObject(automatonsMapping);
		s.flush();
		s.close();
		
		AddLogEntry("finish to serialize " + String.valueOf(numberOfAutomatons) + " automatons in " + String.valueOf(timeCounter.Toc()) + " ms");
	}
	
	public void SerializeDocumentAutomatons(String xmlPath) throws Exception
	{
		RouteToIdIndex routeIndex = new RouteToIdIndex();
		routeIndex.AttachLogger(_logger);
		routeIndex.LoadXml(xmlPath);
		SerializeDocumentAutomatons(routeIndex);
	}
	
	public Automaton DeserializeNodeAutomaton(int nodeIndex) throws Exception
	{
		String automatonPath = _path + String.valueOf(nodeIndex) + ".dfa";
		
		FileInputStream fis = new FileInputStream(automatonPath);
		
		Automaton A = Automaton.load(fis);
				
		fis.close();
		
		return A;
	}
	
	
	public static void main(String[] args) throws Exception
	{
		MyLogger log = new MyLogger("D:\\development\\dblab\\automatonsDB\\log.log");
		
		ArrayList<Integer> posExamples = new ArrayList<Integer>();
		ArrayList<Integer> negExamples = new ArrayList<Integer>();
		posExamples.add(4);
		posExamples.add(8);
		ArrayList<Automaton> negExamplesAutomaton = new ArrayList<Automaton>();
		
		XmlAutomatonManager m = new XmlAutomatonManager("D:\\development\\dblab\\workingDirectory");
		m.AttachLogger(log);
		//m.SerializeDocumentAutomatons("D:\\Downloads\\SwissProt.xml");
		//System.exit(0);
		HashMap<Integer, Integer> mm = m.DeserializeAutomationMapping();
		//mm.get("");
		Automaton posAutomaton = new Automaton();
		
		
		//create the all pos automaton intersection automaton
		if (posExamples.size() != 0)
		{
			posAutomaton = m.DeserializeNodeAutomaton(posExamples.get(0));
		}
		
		for(Integer nodeIndex:posExamples)
		{
			posAutomaton = posAutomaton.intersection(m.DeserializeNodeAutomaton(mm.get(nodeIndex)));
		}
		
		//create the all neg automaton union automaton
		for(Integer nodeIndex:negExamples)
		{
			negExamplesAutomaton.add(m.DeserializeNodeAutomaton(mm.get(nodeIndex)));
		}
		
		Automaton negAutomaton = Automaton.union(negExamplesAutomaton);
		
		//intersect the intersection of all pos automatons with the complement of the union of all
		//neg automatons
		Automaton queryClassifier = posAutomaton.intersection(negAutomaton.complement());

		
		
		//now, if we want to answer whether node n is certain answer, we should 
		//generate the query automaton for n and check if the intersection of the
		//automaton with queryClassifier is not empty
		
		
		Automaton x4 = m.DeserializeNodeAutomaton(mm.get(4));
		Automaton x5 = m.DeserializeNodeAutomaton(mm.get(5));
		Automaton x8 = m.DeserializeNodeAutomaton(mm.get(8));
		Automaton x12 = m.DeserializeNodeAutomaton(mm.get(12));
		Automaton x13 = m.DeserializeNodeAutomaton(mm.get(13));
		Automaton x15 = m.DeserializeNodeAutomaton(mm.get(15));
		
		
		Automaton finalA = x4.intersection(x8);//.intersection(x13.complement());
		
		Automaton c = x5;
		System.out.println(finalA.intersection(c).isEmpty());
		System.out.println(finalA.subsetOf(c));
		System.out.println(c.subsetOf(finalA));
		System.out.println(finalA.intersection(c).getFiniteStrings());
		
			
	}
	
	

}
